package xmpp.client.demo;

import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
import javax.net.ssl.X509TrustManager;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.jivesoftware.smack.ConnectionConfiguration.SecurityMode;
import org.jivesoftware.smack.ConnectionListener;
import org.jivesoftware.smack.ReconnectionListener;
import org.jivesoftware.smack.ReconnectionManager;
import org.jivesoftware.smack.ReconnectionManager.ReconnectionPolicy;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.chat2.Chat;
import org.jivesoftware.smack.chat2.ChatManager;
import org.jivesoftware.smack.tcp.XMPPTCPConnection;
import org.jivesoftware.smack.tcp.XMPPTCPConnectionConfiguration;
import org.jivesoftware.smackx.pubsub.Node;
import org.jivesoftware.smackx.pubsub.PayloadItem;
import org.jivesoftware.smackx.pubsub.PubSubManager;
import org.jivesoftware.smackx.pubsub.SimplePayload;
import org.jivesoftware.smackx.pubsub.listener.ItemEventListener;
import org.jxmpp.jid.EntityJid;
import org.jxmpp.jid.impl.JidCreate;

/**
 * .
 * @author Caspar
 *
 */
@Slf4j
public class XmppClientDemoApplication {


  private static String USRE_NAME = "user44";
  private static String PASSWORD = "user";
  private static String HOST = "im.com";
  private static String XMPP_DOMAIN = "im.com";
  private static String SUBSCRIBE_NODE = "pubsub.test";


  @SneakyThrows
  public static void main(String[] args) {
    //test_sendMsg2();

    // test_sendMsg();

    test_pubsub_subscribe();

    test_pubsub_subscribe2();

    while (true) {
      System.out.println("等待...");
      TimeUnit.MINUTES.sleep(1);
    }
  }

  @SneakyThrows
  private static void test_sendMsg() {
    XMPPTCPConnectionConfiguration connectionConfiguration = XMPPTCPConnectionConfiguration.builder()
        .setHost(HOST)
        .setXmppDomain(XMPP_DOMAIN)
        .setSecurityMode(SecurityMode.ifpossible)
        .setCustomX509TrustManager(new X509TrustManager() {
          @Override
          public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {

          }

          @Override
          public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {

          }

          @Override
          public X509Certificate[] getAcceptedIssuers() {
            return new X509Certificate[0];
          }
        })
        .setPort(5222)
        .setUsernameAndPassword(USRE_NAME, PASSWORD)
        .build();
    XMPPTCPConnection connection = new XMPPTCPConnection(connectionConfiguration);
    connection.setUseStreamManagement(false);
    connection.setUseStreamManagementResumption(false);
    connection.connect();
    connection.login();
    ChatManager chatManager = ChatManager.getInstanceFor(connection);
    Chat chat = chatManager.chatWith(JidCreate.entityBareFrom("user2@im.com"));
    chat.send("from demo");
  }

  @SneakyThrows
  private static void test_pubsub_subscribe() {
    XMPPTCPConnectionConfiguration connectionConfiguration = XMPPTCPConnectionConfiguration.builder()
        .setHost("im.com")
        .setXmppDomain("im.com")
        .setSecurityMode(SecurityMode.ifpossible)
        .setUsernameAndPassword("user44", "user")
        .setCustomX509TrustManager(new AllAllowX509TrustManager())
        .setPort(5222)
        .build();
    XMPPTCPConnection connection = getConnection(connectionConfiguration);
    connection
        .connect()
        .login();

    PubSubManager manager = PubSubManager.getInstanceFor(connection, JidCreate.bareFrom("pubsub.localhost"));
    System.out.println("尝试获取node: ");

    Node eventNode = manager.getNode("test_node.im.com");

    eventNode.addItemEventListener((ItemEventListener<PayloadItem<SimplePayload>>) evt -> {
      System.out.println("user44 收到订阅的载荷数量=" + evt.getItems().size());
      for (PayloadItem<SimplePayload> item : evt.getItems()) {

        System.out.println("user44 订阅项目=" + item.getPayload().toString());
      }
    });
    eventNode.subscribe(connection.getUser().asEntityBareJidString());

  }

  @SneakyThrows
  private static void test_pubsub_subscribe2() {
    XMPPTCPConnectionConfiguration connectionConfiguration = XMPPTCPConnectionConfiguration.builder()
        .setHost("im.com")
        .setXmppDomain("im.com")
        .setSecurityMode(SecurityMode.ifpossible)
        .setUsernameAndPassword("user2", "user")
        .setCustomX509TrustManager(new AllAllowX509TrustManager())
        .setPort(5222)
        .build();
    XMPPTCPConnection connection = getConnection(connectionConfiguration);
    connection
        .connect()
        .login();

    PubSubManager manager = PubSubManager.getInstanceFor(connection, JidCreate.bareFrom("pubsub.localhost"));
    System.out.println("尝试获取node: ");

    Node eventNode = manager.getNode("test_node.im.com");

    eventNode.addItemEventListener((ItemEventListener<PayloadItem<SimplePayload>>) evt -> {
      System.out.println("user2 收到订阅的载荷数量=" + evt.getItems().size());
      for (PayloadItem<SimplePayload> item : evt.getItems()) {

        System.out.println("user2 订阅项目=" + item.getPayload().toString());
      }
    });
    eventNode.subscribe(connection.getUser());

  }

  private static XMPPTCPConnection getConnection(XMPPTCPConnectionConfiguration connectionConfiguration) {
    XMPPTCPConnection connection = new XMPPTCPConnection(connectionConfiguration);
    connection.addConnectionListener(getConnectionListener());
    ReconnectionManager reconnectionManager = ReconnectionManager.getInstanceFor(connection);
    reconnectionManager.setFixedDelay(5);
    reconnectionManager.setReconnectionPolicy(ReconnectionPolicy.FIXED_DELAY);
    reconnectionManager.enableAutomaticReconnection();
    reconnectionManager.addReconnectionListener(new ReconnectionListener() {
      @Override
      public void reconnectingIn(int seconds) {
        System.out.println("重连中...");
      }

      @Override
      public void reconnectionFailed(Exception e) {
        System.out.println("重连失败");
      }
    });
    return connection;
  }


  private static ConnectionListener getConnectionListener() {
    return new ConnectionListener() {
      private String userId = "";

      private void setUserId(XMPPConnection connection) {
        userId = Optional.ofNullable(connection)
            .map(XMPPConnection::getUser)
            .map(EntityJid::toString)
            .orElse("");
      }

      @Override
      public void connecting(XMPPConnection connection) {
        this.setUserId(connection);
        System.out.println(userId + "连接中...");
        ConnectionListener.super.connecting(connection);
      }

      @Override
      public void connected(XMPPConnection connection) {
        this.setUserId(connection);
        System.out.println(userId + "连接成功");
        ConnectionListener.super.connected(connection);
      }

      @Override
      public void authenticated(XMPPConnection connection, boolean resumed) {
        this.setUserId(connection);
        System.out.println(userId + "连接认证成功");
        ConnectionListener.super.authenticated(connection, resumed);
      }

      @Override
      public void connectionClosed() {
        System.out.println(userId + "连接关闭");
        ConnectionListener.super.connectionClosed();
      }

      @Override
      public void connectionClosedOnError(Exception e) {
        System.out.println(userId + "连接异常关闭");
        ConnectionListener.super.connectionClosedOnError(e);
      }
    };
  }
}
